const http = require('http');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const https = require('https');
const crypto = require('crypto');

// 生成16位随机数字
function generateRandomNumber() {
  return Math.random().toString().slice(2, 18).padEnd(16, '0');
}

// 复制目录
function copyDirectory(src, dest) {
  return new Promise((resolve, reject) => {
    // 创建目标目录
    if (!fs.existsSync(dest)) {
      fs.mkdirSync(dest, { recursive: true });
    }

    fs.readdir(src, (err, files) => {
      if (err) {
        reject(err);
        return;
      }

      let pending = files.length;
      if (pending === 0) {
        resolve();
        return;
      }

      files.forEach(file => {
        const srcPath = path.join(src, file);
        const destPath = path.join(dest, file);

        fs.stat(srcPath, (err, stats) => {
          if (err) {
            reject(err);
            return;
          }

          if (stats.isDirectory()) {
            copyDirectory(srcPath, destPath)
              .then(() => {
                pending--;
                if (pending === 0) resolve();
              })
              .catch(reject);
          } else {
            fs.copyFile(srcPath, destPath, err => {
              if (err) {
                reject(err);
                return;
              }
              pending--;
              if (pending === 0) resolve();
            });
          }
        });
      });
    });
  });
}

// 替换文件中的占位符
function replacePlaceholders(filePath, replacements) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) {
        reject(err);
        return;
      }

      let content = data;
      for (const [placeholder, value] of Object.entries(replacements)) {
        const regex = new RegExp(`{{{{${placeholder}}}}}`, 'g');
        content = content.replace(regex, value);
      }

      fs.writeFile(filePath, content, 'utf8', err => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  });
}

// 下载文件
function downloadFile(url, dest) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(dest);
    
    const request = https.get(url, response => {
      if (response.statusCode !== 200) {
        reject(new Error(`下载失败，状态码: ${response.statusCode}`));
        return;
      }
      
      response.pipe(file);
      
      file.on('finish', () => {
        file.close();
        resolve();
      });
    });
    
    request.on('error', err => {
      fs.unlink(dest, () => {}); // 删除部分下载的文件
      reject(err);
    });
    
    file.on('error', err => {
      fs.unlink(dest, () => {}); // 删除部分下载的文件
      reject(err);
    });
  });
}

// 执行命令
function executeCommand(command, cwd) {
  return new Promise((resolve, reject) => {
    exec(command, { cwd }, (error, stdout, stderr) => {
      if (error) {
        reject(error);
        return;
      }
      resolve({ stdout, stderr });
    });
  });
}

// 主要处理函数
async function processDeployment(params) {
  try {
    console.log('开始处理微信小程序部署请求...');
    
    // 第一步：生成随机目录名并复制文件
    const randomNumber = generateRandomNumber();
    const newDirName = `mp-weixin-${randomNumber}`;
    const sourcePath = path.join(__dirname, 'mp-weixin');
    const targetPath = path.join(__dirname, newDirName);
    
    console.log(`复制目录从 ${sourcePath} 到 ${targetPath}`);
    await copyDirectory(sourcePath, targetPath);
    
    // 上传步骤是否执行（仅在提供上传秘钥URL时执行上传）
    const willUpload = Boolean(params.upload_key_url);

    // 第二步：准备占位符替换映射
    const replacements = {
      // 仅注入 appId 与 orgId，占位符减少以避免敏感信息进入前端产物
      'wechat_appid': params.wechat_appid,
      'org_id': params.ORG_ID || params.orgId || params.org_id
    };
    
    // 替换 /common/vendor.js 中的占位符
    const vendorJsPath = path.join(targetPath, 'common', 'vendor.js');
    if (fs.existsSync(vendorJsPath)) {
      console.log('替换 vendor.js 中的占位符...');
      await replacePlaceholders(vendorJsPath, replacements);
    }
    
    // 第三步：更新 project.config.json
    const projectConfigPath = path.join(targetPath, 'project.config.json');
    if (fs.existsSync(projectConfigPath)) {
      console.log('更新 project.config.json...');
      const projectReplacements = {
        'wechat_appid': params.wechat_appid
        // 不再替换 wechat_name，避免不必要的敏感或个性化信息注入
      };
      await replacePlaceholders(projectConfigPath, projectReplacements);
    }
    
    // 第四步：更新 upload.js
    const uploadJsPath = path.join(targetPath, 'upload.js');
    if (fs.existsSync(uploadJsPath)) {
      console.log('更新 upload.js...');
      const uploadReplacements = {
        'wechat_appid': params.wechat_appid
      };
      await replacePlaceholders(uploadJsPath, uploadReplacements);
    }
    
    // 第五步（可选）：下载证书文件（仅当 willUpload 为 true）
    if (willUpload && params.upload_key_url) {
      console.log('下载证书文件...');
      const keyFileName = `private.{{{{wechat_appid}}}}.key`;
      const keyFilePath = path.join(targetPath, keyFileName);
      await downloadFile(params.upload_key_url, keyFilePath);
      
      // 下载完成后，替换文件名中的占位符
      const finalKeyFileName = `private.${params.wechat_appid}.key`;
      const finalKeyFilePath = path.join(targetPath, finalKeyFileName);
      
      // 重命名文件
      if (fs.existsSync(keyFilePath)) {
        fs.renameSync(keyFilePath, finalKeyFilePath);
        console.log(`证书文件已重命名为: ${finalKeyFileName}`);
      }
    }
    
    // 第六步（可选）：安装依赖，仅在需要上传时执行
    if (willUpload) {
      console.log('安装 miniprogram-ci 依赖...');
      await executeCommand('cmd /c pnpm install miniprogram-ci', targetPath);
    }
    
    let uploadResult = null;
    if (willUpload) {
      // 第七步（可选）：执行上传
      console.log('开始上传小程序...');
      uploadResult = await executeCommand('node upload.js upload', targetPath);
      console.log('上传成功！');
      console.log('上传结果:', uploadResult.stdout);
    } else {
      console.log('未提供 upload_key_url，跳过上传步骤，仅完成占位符替换。');
    }
    
    // 调用部署完成回调接口
    if (willUpload && params.id) {
      try {
        console.log('调用部署完成回调接口，ID:', params.id);
        const callbackUrl = `http://localhost:8880/fun/deploymentLog/callback/${params.id}`;
        const callbackResponse = await fetch(callbackUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          }
        });
        
        if (callbackResponse.ok) {
           const callbackResult = await callbackResponse.json();
           console.log('回调接口调用成功:', callbackResult);
           
           // 回调成功后清理临时目录
           console.log('清理临时目录:', targetPath);
           fs.rmSync(targetPath, { recursive: true, force: true });
           console.log('临时目录清理完成');
         } else {
           console.error('回调接口调用失败，状态码:', callbackResponse.status);
         }
       } catch (error) {
         console.error('调用回调接口时发生错误:', error.message);
       }
     }
    
    return {
      success: true,
      message: willUpload ? '小程序上传成功' : '占位符替换完成（未执行上传）',
      data: {
        directory: newDirName,
        uploadAttempted: willUpload,
        uploadResult: uploadResult ? uploadResult.stdout : undefined
      }
    };
    
  } catch (error) {
    console.error('处理失败:', error.message);
    
    // 调用部署失败回调接口（仅在尝试了上传的情况下）
    if (willUpload && params.id) {
      try {
        console.log('调用部署失败回调接口，ID:', params.id);
        const failureCallbackUrl = `http://localhost:8880/fun/deploymentLog/callback/failure/${params.id}`;
        const failureCallbackResponse = await fetch(failureCallbackUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(error.message)
        });
        
        if (failureCallbackResponse.ok) {
          const failureCallbackResult = await failureCallbackResponse.json();
          console.log('失败回调接口调用成功:', failureCallbackResult);
        } else {
          console.error('失败回调接口调用失败，状态码:', failureCallbackResponse.status);
        }
      } catch (callbackError) {
        console.error('调用失败回调接口时发生错误:', callbackError.message);
      }
    }
    
    return {
      success: false,
      message: error.message,
      error: error.stack
    };
  }
}

// 创建HTTP服务器
const server = http.createServer(async (req, res) => {
  // 设置CORS头
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  
  // 处理OPTIONS请求
  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }
  
  // 只处理POST请求
  if (req.method !== 'POST') {
    res.writeHead(405);
    res.end(JSON.stringify({ success: false, message: '只支持POST请求' }));
    return;
  }
  
  // 读取请求体
  const chunks = [];
  let totalLength = 0;
  let contentLength = parseInt(req.headers['content-length'] || '0');
  console.log('期望接收数据长度:', contentLength);
  
  req.on('data', chunk => {
    chunks.push(chunk);
    totalLength += chunk.length;
    console.log(`接收数据块，当前长度: ${totalLength}/${contentLength}`);
  });
  
  // 设置请求超时
  req.setTimeout(30000);
  
  req.on('timeout', () => {
    console.log('请求超时');
    res.writeHead(408, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ success: false, message: '请求超时' }));
  });
  
  req.on('end', async () => {
    try {
      // 合并所有数据块
      const bodyBuffer = Buffer.concat(chunks);
      
      // 直接使用Buffer的完整内容，不依赖Content-Length
      const body = bodyBuffer.toString('utf8');
      
      // 打印接收到的原始数据用于调试
      console.log('接收到的Buffer长度:', bodyBuffer.length);
      console.log('转换为字符串长度:', body.length);
      console.log('原始数据前100字符:', body.substring(0, 100));
      console.log('原始数据后100字符:', body.substring(body.length - 100));
      
      // 解析请求参数
      const params = JSON.parse(body);
      
      // 验证必需参数（仅需 appId 与 orgId）
      const requiredParams = ['wechat_appid', 'ORG_ID'];
      for (const param of requiredParams) {
        if (!params[param]) {
          res.writeHead(400);
          res.end(JSON.stringify({ 
            success: false, 
            message: `缺少必需参数: ${param}` 
          }));
          return;
        }
      }
      
      // 处理部署请求
      const result = await processDeployment(params);
      
      res.writeHead(result.success ? 200 : 500);
      res.end(JSON.stringify(result));
      
    } catch (error) {
      console.error('请求处理错误:', error);
      res.writeHead(400);
      res.end(JSON.stringify({ 
        success: false, 
        message: '请求参数解析失败', 
        error: error.message 
      }));
    }
  });
});

// 启动服务器
const PORT = 3000;
server.listen(PORT, '127.0.0.1', () => {
  console.log(`微信小程序部署服务器已启动，监听地址: http://127.0.0.1:${PORT}`);
  console.log('服务器仅供内部调用，不对外开放端口');
});

// 优雅关闭
process.on('SIGTERM', () => {
  console.log('收到SIGTERM信号，正在关闭服务器...');
  server.close(() => {
    console.log('服务器已关闭');
    process.exit(0);
  });
});

process.on('SIGINT', () => {
  console.log('收到SIGINT信号，正在关闭服务器...');
  server.close(() => {
    console.log('服务器已关闭');
    process.exit(0);
  });
});
